module systolic #(//no expshare
    parameter EXP_Wid = 3  ,
    parameter MSA_Wid = 3  ,
    parameter OUT_Wid = 2 * (2 ** EXP_Wid + MSA_Wid - 1),
    parameter SUM_Wid = OUT_Wid
)(
    input                                   clk     ,

	input		[EXP_Wid+MSA_Wid:0] 		a		,
	input		[EXP_Wid+MSA_Wid:0] 		b		,
	output reg  [SUM_Wid-1:0] 	            result	,

    input                                   out_en  ,
	output reg  [EXP_Wid+MSA_Wid:0] 		a_out	,
	output reg  [EXP_Wid+MSA_Wid:0] 		b_out	,
	input       [SUM_Wid-1:0] 	            result_in
);

wire                    sign_a  = a[EXP_Wid + MSA_Wid               ];
wire [EXP_Wid-1:0]      exp_a   = a[MSA_Wid             +: EXP_Wid  ];
wire [MSA_Wid-1:0]      msa_a   = a[0                   +: MSA_Wid  ];
wire                    sign_b  = b[EXP_Wid + MSA_Wid               ];
wire [EXP_Wid-1:0]      exp_b   = b[MSA_Wid             +: EXP_Wid  ];
wire [MSA_Wid-1:0]      msa_b   = b[0                   +: MSA_Wid  ];

wire [EXP_Wid:0]        exp_sum = exp_a + exp_b;
wire [2*MSA_Wid-1:0]    msa_product = msa_a * msa_b;

wire                    sign_y  = sign_a ^ sign_b;
wire [OUT_Wid-1:0]      y       = msa_product << exp_sum;

always @(posedge clk) begin
    a_out <= a;
    b_out <= b;
end

always @(posedge clk) begin
    if (out_en)
        result <= result_in;
    else
        result <= sign_y ?  (result - y) : (result + y);
end
endmodule

module systolic_expshare #(// expshare 1
    parameter EXP_Wid = 3  ,
    parameter MSA_Wid = 3  ,
    parameter Eshare_Wid = 3,
    parameter OUT_Wid = 2 * (2 ** EXP_Wid + MSA_Wid - 1 + 2 ** Eshare_Wid - 1),
    parameter SUM_Wid = OUT_Wid,
    parameter Fra_Wid = 0
)(
    input                                   clk     ,

	input		[EXP_Wid+MSA_Wid:0] 		a		,
	input		[EXP_Wid+MSA_Wid:0] 		b		,
	output reg  [SUM_Wid-Fra_Wid-1:0] 	    result	,

    input       [Eshare_Wid:0]              exp_share,

    input                                   out_en  ,
	output reg  [EXP_Wid+MSA_Wid:0] 		a_out	,
	output reg  [EXP_Wid+MSA_Wid:0] 		b_out	,
	input       [SUM_Wid-Fra_Wid-1:0] 	    result_in
);

wire                    sign_a  = a[EXP_Wid + MSA_Wid               ];
wire [EXP_Wid-1:0]      exp_a   = a[MSA_Wid             +: EXP_Wid  ];
wire [MSA_Wid-1:0]      msa_a   = a[0                   +: MSA_Wid  ];
wire                    sign_b  = b[EXP_Wid + MSA_Wid               ];
wire [EXP_Wid-1:0]      exp_b   = b[MSA_Wid             +: EXP_Wid  ];
wire [MSA_Wid-1:0]      msa_b   = b[0                   +: MSA_Wid  ];

wire [EXP_Wid+1:0]      exp_sum = exp_a + exp_b + exp_share;//7+7+7+7=28
wire [2*MSA_Wid-1:0]    msa_product = msa_a * msa_b;//[5:0]=6bit

wire                    sign_y  = sign_a ^ sign_b;
wire [OUT_Wid-1:0]      y       = msa_product << exp_sum;

always @(posedge clk) begin
    a_out <= a;
    b_out <= b;
end

always @(posedge clk) begin
    if (out_en)
        result <= result_in;
    else
        result <= sign_y ?  (result - y[OUT_Wid-1:Fra_Wid]) : (result + y[OUT_Wid-1:Fra_Wid]);
end
endmodule
